四、组件化和属性(props)
组件允许您将UI拆分为独立的可重用的部分,并单独地考虑每个部分。
从概念上讲,组件就像JavaScript函数。 它们接受任意输入(称为“props”),并返回应该出现在屏幕上的React元素。功能性组件(functional)和类组件(class component)
定义组件的最简单的方法是编写JavaScript函数:
function Welcome(props) { returnhello, {props.name}
}
此函数是个有效的React组件,因为它接收一个带有数据的“props”对象作为参数,并返回一个React元素。 我们把这样的组件称为“功能性组件(functional)”,因为它们是个JavaScript函数。
您还可以使用ES6类来定义组件:
class Welcome extends React.Component { render() { returnhello, {this.props.name}
; }}
上述两个组件从React的角度来看是等效的。
类组件有一些额外的功能,我们将在下面的章节中讨论。 在那之前,我们将简单地使用功能组件。
渲染一个组件
以前,我们只遇到使用DOM标签的React元素:
const element = ;
但是,元素也可以表示用户自定义的组件:
const element =;
当React看到表示用户定义组件的元素时,它将该JSX标签的所以属性放到一个对象中传递给组件。 我们称这个对象为“props”。
例如,此代码在页面上呈现“Hello,zhangyatao”:
function Welcome(props) { returnHello, {props.name}
;}const element =;ReactDOM.render( element, document.getElementById('root'));
让我们回顾一下在这个例子中发生了什么:
首先调用
ReactDOM.render()
方法,并处理<Welcome name =“zhangyatao”/>
组件。React使用
{name:'zhangyatao'}
作为props调用Welcome
组件。我们的
Welcome
组件返回一个<h1> Hello,zhangyatao </ h1>
元素作为结果。React DOM有效地根据
<h1> Hello,zhangyatao </ h1>
来更新DOM。
警告
组件名称始终使用·首字母大写·。例如,<div />
表示一个DOM标签,但<Welcome />
表示一个组件,并要求Welcome
必须和ReactDOM在一个作用域内。
编写组件
组件可以在其返回值中引用去其他组件。 这允许我们对任何级别的细节使用相同的组件抽象。 一个按钮,一个表单,一个对话框,一个屏幕:在React应用程序中,所有这些通常表示为组件。
例如,我们可以创建一个App组件,让它渲染多个Welcome
组件: function Welcome(props) { returnHello, {props.name}
;}function App() { return ();}ReactDOM.render(, document.getElementById('root'));
这个新的React应用程序在顶部有一个单独的App
组件。
警告
引用多个组件时必须包裹在一个根元素中返回。 这就是为什么我们添加了一个<div>
来包含所有<Welcome />
元素。
抽离组件
永远不要害怕将组件拆分成更小的组件。
例如,考虑这个Comment
组件: import React from 'react';import ReactDOM from 'react-dom';function formatDate(date) { return date.toISOString();}function Comment(props) { return ();}ReactDOM.render({props.author.name}{props.text}{formatDate(props.date)}, document.getElementById('root'));
它接受author
(作者),text
(内容)和date
(日期)作为props,用来描述社交媒体网站上的评论。
首先,我们将提取avatar
:
function Avatar(props) { return ( );}
avatar
不需要知道它正在Comment
中呈现。 这就是为什么我们给它的prop一个更通用的名称:user
而不是author
。
我们现在可以对Comment
组件做一点点简化:
function Comment(props) { return ();} {props.author.name}{props.text}{formatDate(props.date)}
接下来,我们将提取一个UserInfo
组件,该组件在用户名称旁边呈现一个avatar
:
function UserInfo(props) { return ();} {props.user.name}
这使我们可以进一步简化Comment
组件:
function Comment(props) { return ();} {props.text}{formatDate(props.date)}
最终的代码如下:
import React from 'react';import ReactDOM from 'react-dom';function formatDate(date) { return date.toISOString();}function Avatar(props) { return ( );}function UserInfo(props) { return ();}function Comment(props) { return ( {props.user.name});}ReactDOM.render( {props.text}{formatDate(props.date)}, document.getElementById('root'));
让一个个可重用组件在大型应用程序中交付使用的过程中,抽离组件起初可能看起来像又脏又累的活儿。 所以有一个好的经验法则:如果UI的一部分被使用了好几次(按钮,面板,头像),或者内部比较复杂的东西(App,FeedStory,评论),一个可重用的组件对它来说可以达到最大的发挥空间。
Props是只读的
无论是将组件声明为功能组件还是类组件,它都不能修改自己的props。 考虑这个计算参数总和的函数:
function sum(a, b) { return a + b;}
这样的函数被称为“纯函数”
,因为它们不会改变它们的参数值,并且对于相同的输入总是返回相同的结果。
function withdraw(account, amount) { account.total -= amount;}
React非常灵活,但它有一个严格的规则:
所有React组件必须像它们的porps的纯函数那样运行。当然,应用中的UI大部分是动态的,随时间变化。 在下一节中,我们将介绍一个“state”的新概念。 状态允许React组件响应用户操作,网络响应和其他任何内容,随时间更改其输出,而不违反此规则。